package com.winbaoxian.testng.core.action;

import com.alibaba.fastjson.JSON;
import com.winbaoxian.common.freemarker.utils.JsonUtils;
import com.winbaoxian.testng.core.common.ParamsExecutor;
import com.winbaoxian.testng.enums.ActionType;
import com.winbaoxian.testng.model.core.ActionConfigDTO;
import com.winbaoxian.testng.model.core.TestCasesContext;
import com.winbaoxian.testng.model.core.action.*;
import com.winbaoxian.testng.model.core.log.TestReportDataTestCaseDTO;
import com.winbaoxian.testng.utils.ConsoleLogUtils;
import com.winbaoxian.testng.utils.WinTestNGLogUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author dongxuanliang252
 * @date 2019-03-05 14:28
 */
@Component
@Slf4j
public class ActionExecutor {

    @Resource
    private HttpAction httpAction;
    @Resource
    private ResourceAction resourceAction;
    @Resource
    private SetvAction setvAction;
    @Resource
    private TplAction tplAction;
    @Resource
    private AssertionAction assertionAction;
    @Resource
    private ParamsExecutor paramsExecutor;

    public void execute(List<ActionConfigDTO> configList, TestCasesContext context) throws Exception {
        if (CollectionUtils.isEmpty(configList)) {
            return;
        }
        TestReportDataTestCaseDTO reportDataContext = context.getReportDataContext();
        for (ActionConfigDTO actionConfig : configList) {
            String tFlowActionLogPrefix = WinTestNGLogUtils.INSTANCE.getActionLogPrefix(actionConfig, context);
            String[] testReportTitles = WinTestNGLogUtils.INSTANCE.getTestReportTitles(actionConfig, context);
            log.info("[{}]execute action start", tFlowActionLogPrefix);
            ConsoleLogUtils.INSTANCE.log(reportDataContext.getReportUuid(), String.format("[%s]execute action start", tFlowActionLogPrefix));
            reportDataContext.logText("开始执行", testReportTitles);
            Object ret = null;
            try {
                ret = execute(actionConfig, context);
            } catch (Exception e) {
                reportDataContext.logException(e, testReportTitles);
                throw e;
            }
            if (StringUtils.isNotBlank(actionConfig.getAlias())) {
                context.addGlobalParams(actionConfig.getAlias(), ret);
            }
            //记录noticeMsg
            logActionNoticeMsg(actionConfig, context, ret);
            log.info("[{}]execute action end, alias:{}, return:{}", tFlowActionLogPrefix, actionConfig.getAlias(), JsonUtils.INSTANCE.toJSONString(ret));
            ConsoleLogUtils.INSTANCE.log(reportDataContext.getReportUuid(), String.format("[%s]execute action end, alias:%s, return:%s", tFlowActionLogPrefix, actionConfig.getAlias(), JsonUtils.INSTANCE.toJSONString(ret)));
            reportDataContext.logText(String.format("执行完成, 别名:%s, 数据:%s", actionConfig.getAlias(), JsonUtils.INSTANCE.toPrettyJSONString(ret)), testReportTitles);
            Long delayTimes = actionConfig.getDelayTimes();
            if (delayTimes != null && delayTimes > 0) {
                Thread.sleep(actionConfig.getDelayTimes());
                log.info("[{}]after execute action, delay times:{}ms", tFlowActionLogPrefix, delayTimes);
                ConsoleLogUtils.INSTANCE.log(reportDataContext.getReportUuid(), String.format("[%s]after execute action, delay times:%sms", tFlowActionLogPrefix, delayTimes));
                reportDataContext.logText(String.format("延迟, delay times:%s(ms)", delayTimes), testReportTitles);
            }
        }
    }

    private Object execute(ActionConfigDTO actionConfig, TestCasesContext context) throws Exception {
        if (actionConfig == null || StringUtils.isBlank(actionConfig.getSettings())) {
            return null;
        }
        //参数替换
        String tFlowActionLogPrefix = WinTestNGLogUtils.INSTANCE.getActionLogPrefix(actionConfig, context);
        String[] testReportTitles = WinTestNGLogUtils.INSTANCE.getTestReportTitles(actionConfig, context);
        TestReportDataTestCaseDTO reportDataContext = context.getReportDataContext();
        String actionSettingsStr = actionConfig.getSettings();
        if (StringUtils.isBlank(actionSettingsStr)) {
            return null;
        }
        ActionType actionType = actionConfig.getActionType();
        //TPL替换
        JSON actionJo;
        if (ActionType.ASSERTION.equals(actionType)) {
            actionJo = JSON.parseArray(actionSettingsStr);
        } else {
            actionJo = JSON.parseObject(actionSettingsStr);
        }
        paramsExecutor.renderDeep(actionJo, context);
        log.info("[{}]Action配置:{}", tFlowActionLogPrefix, JsonUtils.INSTANCE.toJSONString(actionJo));
        ConsoleLogUtils.INSTANCE.log(reportDataContext.getReportUuid(), String.format("[%s]Action配置:%s", tFlowActionLogPrefix, JsonUtils.INSTANCE.toPrettyJSONString(actionJo)));
        reportDataContext.logText(String.format("Action配置:%s", JsonUtils.INSTANCE.toPrettyJSONString(actionJo)), testReportTitles);
        if (ActionType.HTTP.equals(actionType)) {
            HttpActionSettings settings = JSON.parseObject(actionJo.toJSONString(), HttpActionSettings.class);
            return httpAction.execute(settings, actionConfig, context);
        } else if (ActionType.RESOURCE.equals(actionType)) {
            ResourceActionSettings settings = JSON.parseObject(actionJo.toJSONString(), ResourceActionSettings.class);
            return resourceAction.execute(settings, actionConfig, context);
        } else if (ActionType.SETV.equals(actionType)) {
            SetvActionSettings settings = JSON.parseObject(actionJo.toJSONString(), SetvActionSettings.class);
            return setvAction.execute(settings, actionConfig, context);
        } else if (ActionType.ASSERTION.equals(actionType)) {
            AssertionActionSettings settings = JSON.parseObject(actionJo.toJSONString(), AssertionActionSettings.class);
            return assertionAction.execute(settings, actionConfig, context);
        } else if (ActionType.TPL.equals(actionType)) {
            TplActionSettings settings = JSON.parseObject(actionJo.toJSONString(), TplActionSettings.class);
            return tplAction.execute(settings, actionConfig, context);
        }
        return null;
    }

    private void logActionNoticeMsg(ActionConfigDTO actionConfig, TestCasesContext context, Object ret) {
        String[] testReportTitles = WinTestNGLogUtils.INSTANCE.getTestReportTitles(actionConfig, context);
        TestReportDataTestCaseDTO reportDataContext = context.getReportDataContext();
        String noticeMsg = null;
        if (StringUtils.isBlank(actionConfig.getAlias()) && !ActionType.ASSERTION.equals(actionConfig.getActionType())) {
            noticeMsg = "无别名";
        } else if (ret == null) {
            noticeMsg = "返回null";
        } else if ((ret instanceof Map) && MapUtils.isEmpty((Map) ret)) {
            noticeMsg = "返回空";
        } else if ((ret instanceof Collection) && CollectionUtils.isEmpty((Collection) ret)) {
            noticeMsg = "返回空";
        } else if (ActionType.HTTP.equals(actionConfig.getActionType())) {
            if ((ret instanceof Map) && ((Map) ret).containsKey("statusCode")) {
                noticeMsg = JsonUtils.INSTANCE.toJSONString(((Map) ret).get("statusCode"));
            }
        }
        reportDataContext.logNoticeMsg(noticeMsg, testReportTitles);
    }

}
